﻿using AutoMapper;
using B.S.BaseData.Domain.Entities.RBAC;
using B.S.BaseData.ErrorCode;
using B.S.BaseData.ErrorCode.ErrorCodes;
using B.S.BaseData.Infrastructure.Helper;
using B.S.BaseData.Infrastructure.Interfaces;
using B.S.DataBase.EFCoreServiers.Dtos.Depts;
using B.S.DataBase.EFCoreServiers.IServices.Dtpes;
using CSRedis;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace B.S.DataBase.EFCoreServiers.Services.Depts
{
    public class DepartmentServices : IDepartmentServices
    {

        // 这里可以注入需要的仓储或其他服务
        private readonly IRoleRepository roleRepository;
        private readonly IMapper mapper;
        private readonly IDepartmentRepository deptRep;
        private readonly IUserRepository userRep; // 注入IUserRepository
        private readonly IUserRoleRepository userRole;
        private readonly CSRedisClient cSRedis;
        private readonly RedisHelpers redisHelper;

        public DepartmentServices(IRoleRepository roleRepository, IMapper mapper, IDepartmentRepository deptRep, IUserRepository userRep, IUserRoleRepository userRole, CSRedisClient cSRedis, RedisHelpers redisHelper)
        {
            this.roleRepository = roleRepository;
            this.mapper = mapper;
            this.deptRep = deptRep;
            this.userRep = userRep; // 初始化IUserRepository
            this.userRole = userRole;
            this.cSRedis = cSRedis;
            this.redisHelper = redisHelper;
        }
        /// <summary>
        /// 部门新增
        /// </summary>
        /// <param name="departmentDto"></param>
        /// <returns></returns>
        public async Task<ApiResult> AddDepartmentAsync(AddDepartmentDto departmentDto)
        {
            try
            {
                var existingRole = await deptRep.GetAll().FirstOrDefaultAsync(x => x.DepartmentName == departmentDto.DepartmentName);
                if (existingRole != null)
                {
                    return ApiResult.Fail("部门名称已存在", StatusCodeEnum.Fail);
                }

                var list = mapper.Map<Department>(departmentDto);
                list.Status = 1; // 默认启用状态
                list.MemberCount = 0; // 默认成员数量为0
                // 添加角色并保存更改
                // AddAsync方法内部已经包含了SaveChanges操作，不需要重复调用
                await deptRep.AddAsync(list);

                return ApiResult.Success(StatusCodeEnum.Ok);
            }
            catch (Exception ex)
            {
                return ApiResult.Fail("添加部门失败：" + ex.Message, StatusCodeEnum.Exception);
            }
        }
        /// <summary>
        /// 部门删除
        /// </summary>
        /// <param name="deptId"></param>
        /// <returns></returns>
        public async Task<ApiResult> DeleteDepartmentAsync(int deptId)
        {
            try
            {
                var list = await deptRep.GetAll().FirstOrDefaultAsync(x => x.DeptId == deptId);
                if (list == null)
                {
                    return ApiResult.Fail("部门不存在", StatusCodeEnum.ObjNotFound);
                }
                // 删除角色
                await deptRep.DeleteAsync(list);
                return ApiResult.Success(StatusCodeEnum.Ok);
            }
            catch (Exception ex)
            {
                return ApiResult.Fail("删除部门失败：" + ex.Message, StatusCodeEnum.Exception);
            }
        }
        /// <summary>
        /// 获取部门列表
        /// </summary>
        /// <param name="departmentDto"></param>
        /// <returns></returns>
        public async Task<ApiResult<ApiPaging<GetDepartmentResponseDto>>> GetDepartmentListAsync(GetDepartmentDto departmentDto)
        {
            try
            {
                // 获取部门分页数据
                var deptList = await deptRep.GetPageListAsync(departmentDto.pageIndex,
                     departmentDto.pageSize,
                    x => (x.DepartmentName.Contains(departmentDto.DepartmentName) || string.IsNullOrEmpty(departmentDto.DepartmentName)));

                // 收集所有ManagerId
                var managerIds = deptList.Data.Where(d => d.ManagerId.HasValue).Select(d => d.ManagerId.Value).Distinct().ToList();

                // 批量查询用户
                var users = await userRep.GetAll().Where(u => managerIds.Contains(u.UserId)).ToListAsync();

                // 转换类型
                var dto = mapper.Map<IList<GetDepartmentResponseDto>>(deptList.Data);

                // 收集所有上级部门ID
                var parentIds = deptList.Data.Where(d => d.ParentId.HasValue).Select(d => d.ParentId.Value).Distinct().ToList();

                // 批量查询上级部门
                var parentDepts = await deptRep.GetAll().Where(d => parentIds.Contains(d.DeptId)).ToListAsync();

                // 组装主管名称和上级部门名称
                foreach (var deptDto in dto)
                {
                    // 设置主管名称
                    var user = users.FirstOrDefault(u => u.UserId == deptDto.ManagerId);
                    deptDto.UserName = user?.UserName ?? string.Empty;

                    // 设置上级部门名称
                    var dept = deptList.Data.FirstOrDefault(d => d.DeptId == deptDto.DeptId);
                    if (dept?.ParentId != null)
                    {
                        var parentDept = parentDepts.FirstOrDefault(d => d.DeptId == dept.ParentId);
                        deptDto.ParentDeptName = parentDept?.DepartmentName ?? string.Empty;
                    }
                    else
                    {
                        deptDto.ParentDeptName = string.Empty;
                    }
                }

                ApiPaging<GetDepartmentResponseDto> apiPaging = new ApiPaging<GetDepartmentResponseDto>(deptList.TotalCount, deptList.TotalPage, dto);

                return ApiResult<ApiPaging<GetDepartmentResponseDto>>.Success(apiPaging, StatusCodeEnum.Ok);

            }
            catch (Exception ex)
            {
                return ApiResult<ApiPaging<GetDepartmentResponseDto>>.Fail("获取部门列表失败：" + ex.Message, StatusCodeEnum.Exception);
            }
        }
        /// <summary>
        /// 获取部门树形结构
        /// </summary>
        /// <param name="ParentId"></param>
        /// <returns></returns>
        public async Task<ApiResult<IList<DeptItemTree>>> GetDeptTree(int ParentId = 0)
        {
            var result = await redisHelper.GetOrSetAsync<List<DeptItemTree>>("Meeting_Dept_Tree", async () =>
            {
                // 获取所有部门数据
                var allDepts = await deptRep.GetAll().ToListAsync();

                // 递归构建树形结构
                List<DeptItemTree> BuildTree(int parentId)
                {
                    return allDepts
                        .Where(d => (d.ParentId ?? 0) == parentId)
                        .Select(d => new DeptItemTree
                        {
                            value = d.DeptId,
                            label = d.DepartmentName,
                            children = BuildTree(d.DeptId)
                        })
                        .ToList();
                }
                return BuildTree(ParentId);
            }, TimeSpan.FromHours(2)); // 设置2小时的缓存过期时间

            return ApiResult<IList<DeptItemTree>>.Success(result, StatusCodeEnum.Ok);
        }


        #region 用户部门树形结构获取 /// <summary>
        /// 获取用户部门树形结构，按照一级部门组织用户和角色信息
        /// </summary>
        /// <param name="ParentId">父部门ID，默认为0表示顶级部门</param>
        public async Task<ApiResult<List<UserDeptItemTree>>> GetUserDeptTree(int ParentId = 0)
        {
            try
            {
                // 使用封装的Redis接口
                var result = await redisHelper.GetOrSetAsync<List<UserDeptItemTree>>("Meeting_UserDept_Tree", async () =>
                {
                    // 1. 获取所有一级部门（ParentId为0或null的部门） 顶级部门
                    var topDepts = await deptRep.GetAll()
                        .Where(x => x.ParentId == 0 || x.ParentId == null)
                        .ToListAsync();

                    // 2. 获取角色信息 根据部门id获取角色信息 看该部门下有哪些角色
                    var roles = await roleRepository.GetAll()
                        .Where(r => r.DeptId != null)  // 只获取有部门关联的角色
                        .ToListAsync();

                    // 3.获取所有用户-角色关联数据，用于确定用户的角色 x=>x.RoleId!=6(不显示普通用户，普通用户没有操作权限)
                    var userRoles = await userRole.GetAll().Where(x => x.RoleId != 6).ToListAsync();

                    //  构建树形结构
                    var resultList = new List<UserDeptItemTree>();
                    foreach (var dept in topDepts)//循环所有一级部门
                    {
                        // 创建部门节点
                        var deptNode = new UserDeptItemTree
                        {
                            DeptId = dept.DeptId,
                            DepartmentName = dept.DepartmentName,
                            Children = new List<UserDeptItemTree>()
                        };

                        //  获取该部门下的所有子部门ID（包括自身）
                        var allSubDeptIds = await GetAllSubDeptIds(dept.DeptId);//拿到的是当前部门id（一级部门） 用它来查询它下面 所有的子部门的id

                        //  直接通过角色表的DeptId关联查询 拿到上面的子部门id来查询 看该部门下有哪些角色
                        var deptRoles = roles.Where(r => allSubDeptIds.Contains(r.DeptId));
                        //  获取角色下的用户
                        foreach (var role in deptRoles)
                        {
                            var roleNode = new UserDeptItemTree
                            {
                                RoleId = role.RoleId,
                                RoleName = role.RoleName,
                                // 获取该角色下的所有用户信息 根据角色id查询用户信息 把用户信息放到user里，也就是一级部门下
                                Users = await GetUsersInRole(role.RoleId, userRoles)
                            };
                            // 把用户信息放到user里，也就是一级部门下
                            deptNode.Children.Add(roleNode);
                        }
                        //所有的一级部门信息 
                        resultList.Add(deptNode);
                    }

                    return resultList;
                }, TimeSpan.FromHours(2)); // 设置2小时的缓存过期时间

                return ApiResult<List<UserDeptItemTree>>.Success(result, StatusCodeEnum.Ok);
            }
            catch (Exception ex)
            {
                return ApiResult<List<UserDeptItemTree>>.Fail(
                    "获取部门用户树失败：" + ex.Message,
                    StatusCodeEnum.Exception
                );
            }
        }

        /// <summary>
        /// 递归获取指定部门及其所有子部门的ID列表
        /// </summary>
        /// <param name="deptId">部门ID</param>
        /// <returns>包含当前部门及其所有子部门ID的列表</returns>
        private async Task<List<int>> GetAllSubDeptIds(int deptId)
        {
            // 初始化结果列表，首先添加当前部门ID
            var result = new List<int> { deptId };
            // 获取所有部门数据，避免递归过程中重复查询数据库
            var allDepts = await deptRep.GetAll().ToListAsync();
            // 定义本地递归函数，用于查找子部门
            void AddSubDepts(int parentId)
            {
                // 查找parentId下的所有直接子部门
                var subDepts = allDepts.Where(d => d.ParentId == parentId);
                foreach (var dept in subDepts)
                {
                    // 将子部门ID添加到结果列表
                    result.Add(dept.DeptId);
                    // 递归查找当前子部门的子部门 也就是看当前的一级部门下 的子部门是否还有子部门 全部放入当前一级部门下
                    AddSubDepts(dept.DeptId);
                }
            }
            // 开始递归查找子部门  这里才开始调用方法，传入一个deptid（当前的一级部门id），对子部门进行查询
            AddSubDepts(deptId);
            return result;
        }


        /// <summary>
        /// 获取指定角色下的所有用户信息
        /// </summary>
        /// <param name="roleId">角色ID</param>
        /// <param name="userRoles">用户-角色关联数据</param>
        /// <param name="allUsers">所有用户数据</param>
        /// <returns>用户信息列表</returns>
        private async Task<List<UserInfo>> GetUsersInRole(int roleId, List<UserRole> userRoles)
        {
            // 1. 获取该角色下的所有用户ID
            var userIds = userRoles
                .Where(ur => ur.RoleId == roleId)//根据角色id进行 查询 查到所有的用户id
                .Select(ur => ur.UserId)//只要用户id
                .ToList();

            // 2. 批量查询这些用户的详细信息
            var users = await userRep.GetAll()//查询用户角色映射表
                .Where(u => userIds.Contains(u.UserId))//看上面查到的所以用户id是否包含当前用户id
                .ToListAsync();

            // 3. 转换为UserInfo对象 拿到用户信息后 添加到UserInfo对象中
            return users.Select(user => new UserInfo
            {
                UserId = user.UserId,
                UserName = user.UserName,
                RealName = user.RealName
            }).ToList();
        }
        #endregion

        /// <summary>
        /// 部门更新
        /// </summary>
        /// <param name="departmentDto"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<ApiResult> UpdateDepartmentAsync(UpdateDepartmentDto departmentDto)
        {
            try
            {
                // 判断是否有其他角色使用了相同的角色名称（排除当前角色）
                var exist = await deptRep.GetAll()
                    .AnyAsync(x => x.DepartmentName == departmentDto.DepartmentName && x.DeptId != departmentDto.DeptId);

                if (exist)
                {
                    return ApiResult.Fail("部门名称已存在", StatusCodeEnum.Fail);
                }

                // 获取当前要编辑的角色
                var dept = await deptRep.GetAll().FirstOrDefaultAsync(x => x.DeptId == departmentDto.DeptId);
                if (dept == null)
                {
                    return ApiResult.Fail("部门不存在", StatusCodeEnum.ObjNotFound);
                }
                dept.DepartmentName = departmentDto.DepartmentName;
                dept.ManagerId = departmentDto.ManagerId;
                dept.Description = departmentDto.Description;
                dept.ParentId = departmentDto.ParentId; // 更新父部门ID
                // 更新角色信息
                await deptRep.UpdateAsync(dept);

                return ApiResult.Success(StatusCodeEnum.Ok);
            }
            catch (Exception ex)
            {
                return ApiResult.Fail("编辑部门失败：" + ex.Message, StatusCodeEnum.Exception);
            }
        }

        /// <summary>
        /// 修改部门状态
        /// </summary>
        /// <param name="deptId"></param>
        /// <returns></returns>
        public async Task<ApiResult> UpdateStateDeptAsync(int deptId)
        {
            try
            {
                // 查到当前角色是否存在
                var info = await deptRep.GetAll()
                    .FirstOrDefaultAsync(x => x.DeptId == deptId);

                if (info == null)
                {
                    return ApiResult.Fail("部门不存在", StatusCodeEnum.Fail);
                }

                if (info.Status == 1)
                {
                    info.Status = 0; // 如果当前状态是启用，则改为禁用
                }
                else
                {
                    info.Status = 1; // 如果当前状态是禁用，则改为启用
                }


                await deptRep.UpdateAsync(info);

                return ApiResult.Success(StatusCodeEnum.Ok);
            }
            catch (Exception ex)
            {
                return ApiResult.Fail("修改部门状态失败：" + ex.Message, StatusCodeEnum.Exception);
                ;
            }
        }



    }
}
